# Правила оформления C++ кода

1. [Заголовочные файлы](#1-Заголовочные-файлы)  
   1.1. [Include guards](#11-Include-guards)  
   1.2. [Подключайте то, что используете](#12-Подключайте-то-что-используете)  
   1.3. [Порядок подключения](#13-Порядок-подключения)  
2. [Области видимости](#2-Области-видимости)  
   2.1. [Пространства имён](#21-Пространства-имён)  
   2.2. [Локальные переменные](#22-Локальные-переменные)  
3. [Классы](#3-Классы)
4. [Функции](#4-Функции)
5. [Наименование и синтаксис](#5-Наименование-и-синтаксис)  
   5.1. [Файлы](#51-Файлы)  
   5.2. [Классы и структуры](#52-Классы-и-структуры)  
   5.3. [Функции и методы](#53-Функции-и-методы)  
   5.4. [Перечисления](#54-Перечисления)  
   5.5. [Пространства имён](#55-Пространства-имён)  

## 1. Заголовочные файлы
В общем случае каждому файлу исходного кода (`.cpp`) должен соответствовать заголовочный файл (`.h`). Бывают исключения - например, файл `main.cpp`, который содержит точку входа - функцию `main`

### 1.1. Include guards
Каждый заголовочный файл должен содержать include guard - конструкцию, которая не позволяет подключать файл более одного раза

Если для реализации include guard используются директивы `#ifndef` и `#define`, то название символьной константы должно составляться следующим образом: `<PROJECT>_<PATH>_<FILE>_H_`

Например, для файла `foo\src\bar\baz.h` в проекте `foo`:

**Хорошо**
```cpp
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif  // FOO_BAR_BAZ_H_
```

**Плохо**
```cpp
#ifndef BAZ
#define BAZ
...
#endif  // BAZ
```
### 1.2. Подключайте то, что используете
Если вы пользуетесь какой-то сущностью, объявленной извне - подключайте тот заголовочный файл, в котором эта сущность объявлена. Больше никаких причин для подключения заголовочного файла не существует

Не надейтесь на транзитивные подключения (когда заголовочный файл, который содержит нужную вам сущность, уже подключён в другом заголовочном файле, который вы уже подключили)

```cpp
// bar.h
# pragma once
class Bar { }
```
```cpp
// foo.h
# pragma once
#include "bar.h"
class Foo {
public:
	Foo(Bar bar);
}
```
**Хорошо**
```cpp
// main.cpp
#include "foo.h"
#include "bar.h"

int main(int argc, char** argv) {
	Bar bar;
	Foo foo(bar);
}
```

**Плохо**
```cpp
// main.cpp
#include "foo.h"

int main(int argc, char** argv) {
	Bar bar;
	Foo foo(bar);
}
```
### 1.3. Порядок подключения
Подключайте заголовочные файлы в следующем порядке:
 - ассоциированный с текущим файлом исходного кода заголовочный файл
 - системные заголовочные файлы C
 - заголовочные файлы стандартной библиотеки C++
 - заголовочные файлы остальных библиотек
 - заголовочные файлы вашего проекта

Все вышеперечисленные группы разделяются пустой строкой (в случае, если они не пустые)

Избегайте использования относительных директорий (`.` и `..`) для определения пути к заголовочному файлу вашего проекта - указывайте путь, начиная с корня проекта

Например, блок подключения заголовочных файолов в файле `foo-project/src/foo/internal/fooserver.cpp`

**Хорошо**
```cpp
#include "foo/server/fooserver.h"

#include <sys/types.h>
#include <unistd.h>

#include <string>
#include <vector>

#include "base/basictypes.h"
#include "foo/server/bar.h"
#include "third_party/absl/flags/flag.h"
```
**Плохо**
```cpp
#include <sys/types.h>
#include "foo/server/bar.h"
#include "third_party/absl/flags/flag.h"
#include <unistd.h>
#include "base/basictypes.h"
#include <string>
#include "foo/server/fooserver.h"
#include <vector>
```

## 2. Области видимости
### 2.1. Пространства имён
Правило, для которого есть редкие исключения, гласит - всегда пишите код внутри пространства имён

Пространства имён должны иметь уникальное название, основанное на названии проекта и, по возможности, пути внутри проекта

Не используйте директивы `using` (например, `using namespace foo`)

Не используйте `inline` пространства имён

### 2.2. Локальные переменные
Инициализируйте локальные переменные при объявлении
**Хорошо**
```cpp
int j = g();
```
**Плохо**
```cpp
int i;
i = f();
```

Используйте списки инициализации
**Хорошо**
```cpp
std::vector<int> v = {1, 2};
```
**Плохо**
```cpp
std::vector<int> v;
v.push_back(1);
v.push_back(2);
```

Объявляйте переменные там, где они нужны - в самой узкой области видимости, которая возможна
**Хорошо**
```cpp
while (const char* p = strchr(str, '/')) str = p + 1;
```
**Плохо**
```cpp
const char* p = nullptr;
while (p = strchr(str, '/')) str = p + 1;
```

Есть исключение из этого правила - если переменная является экземпляром класса, и вы объявляете (и создаёте) её в цикле, то конструктор и деструктор этого класса будет вызываться при каждой итерации цикла, что негативно скажется на производительности

**Хорошо**
```cpp
Foo f;
for (int i = 0; i < 1000000; ++i) {
  f.DoSomething(i);
}
```
**Плохо**
```cpp
for (int i = 0; i < 1000000; ++i) {
  Foo f;
  f.DoSomething(i);
}
```

## 3. Классы
Избегайте вызовов виртуальных методов внутри конструктора - во время работы конструктора объект ещё не создан полностью

Избегайте неявных преобразований. Используйте ключевое слово `explicit` для операторов преобразования и конструкторов с одним аргументом

Используйте структуры (`struct`) для классов без поведения, которые нужны только для хранения данных. В остальных случаях используйте классы (`class`)

Композиция (использование экземпляра одного класса внутри другого) часто является более подходящей, нежели наследование. При использовании наследования - делайте его публичным (`public`)

Определение класса обычно начинается с секции `public`, затем идёт `protected` и потом `private`
Внутри каждой секции группируйте члены класса одного рода, придерживаясь следующего порядка:
1. Типы и псевдонимы типов (`typedef`, `using`, `enum`, внутренние структуры и классы, дружественные (`friend`) типы
2. Статические константы
3. Фабричные методы
4. Конструкторы и операторы присвоения
5. Деструктор
6. Остальные методы (статические, нестатические, дружественные)
7. Поля (статические и нестатические)


## 4. Функции
Предпочительнее возвращать результат работы функции с помощью возвращаемого значения, чем с помощью выходного параметра

**Хорошо**
```cpp
int sum(int a, int b);
```
**Плохо**
```cpp
void sum(int a, int b, int& sum);
```

Лучше возвращать результат по значению. Если это невозможно, то лучше по ссылке, чем с помощью указателя. Возвращать значение с помощью указателя можно в случае, если оно может быть равно `nullptr`


Предпочтительнее использовать маленькие однозадачные функции. Если функция получается длинной, подумайте о том, можно ли её разбить на несколько

Не стоит использовать аргументы по умолчанию в виртуальных методах, так как наследники могут переопределить значение по умолчанию, что в итоге может запутать программиста

## 5. Наименование и синтаксис
Все наименования могут содержать в себе буквы латинского алфавита, цифры и символ `_`. При этом никакое название не может начинаться с цифры

Открывающие фигурные скобки следует располагать на той же самой строке, а не на следующей

Внутри блока, заключённого в фигурных скобках, нужно делать отступ - 4 пробела от предыдущего уровня

**Хорошо**
```cpp
void myFunction1() {
    int myVar2 = 5;
}
```
**Плохо**
```cpp
void 1myFunction()
{
int 2myVar = 5;
}
```

### 5.1. Файлы
Название файла должно начинаться с маленькой буквы, отдельные слова разделяются нижним подчёркиванием
**Хорошо**
```
main.cpp
my_header.h
very_complex_name.cpp
```
**Плохо**
```
Main.cpp
my-header.h
veryComplexName.cpp
```

### 5.2. Классы и структуры
Название класса или структуры должно начинаться с большой буквы, отдельные слова начинаются с большой буквы и не отделяются символами
**Хорошо**
```cpp
class MyAwesomeClass {};
```
**Плохо**
```cpp
class my_awesome_class {};
class myAwesomeClass {};
class My_Awesome_Class {};
```

Название полей в классе или структуре должно начинаться с маленькой буквы, отдельные слова начинаются с большой буквы и не отделяются символами

**Хорошо**
```cpp
class MyClass {
    int myField;
};
```
**Плохо**
```cpp
class MyClass {
    int MyField;
    int my_field;
    int My_Field;
};
```

Название константных полей в классе или структуре нужно писать только большими буквами, разделяя отдельные слова нижним подчёркиванием

**Хорошо**
```cpp
class MyClass {
    const int MY_CONST_FIELD;
};
```
**Плохо**
```cpp
class MyClass {
    const int myConstField;
    const int MyConstField;
    const int my_const_field;
    const int My_Const_Field;
};
```

### 5.3. Функции и методы
Название свободной функции или метода (функции - члена класса) должно начинаться с маленькой буквы, отдельные слова начинаются с большой буквы и не отделяются символами
**Хорошо**
```cpp
void myFreeFunction();
class MyAwesomeClass {
    void myMethod();
};
```
**Плохо**
```cpp
void MyFreeFunction();
void my_free_function();
void My_Free_Function();
```

Название аргументов функций и методов должно начинаться с маленькой буквы, отдельные слова начинаются с большой буквы и не отделяются символами

**Хорошо**
```cpp
void myFreeFunction(int firstArg, float secondArg);
```
**Плохо**
```cpp
void myFreeFunction(int first_arg, float second_arg);
void myFreeFunction(int FirstArg, float SecondArg);
void myFreeFunction(int First_Arg, float Second_Arg);
```

Название локальных переменных функций и методов должно начинаться с маленькой буквы, отдельные слова начинаются с большой буквы и не отделяются символами

**Хорошо**
```cpp
void myFreeFunction(int firstArg, float secondArg) {
    int myVar;
}
```
**Плохо**
```cpp
void myFreeFunction(int firstArg, float secondArg) {
    int my_var;
    int MyVar;
    int My_Var;
}
```

### 5.4. Перечисления
Название перечисления должно начинаться с большой буквы, отдельные слова начинаются с большой буквы и не отделяются символами
Названия констант внутри перечисления нужно писать только большими буквами, разделяя отдельные слова нижним подчёркиванием

**Хорошо**
```cpp
enum class MyEnum {
    MY_CONST_1,
    MY_CONST_2,
    MY_CONST_3,
};
```
**Плохо**
```cpp
enum class MY_ENUM {
    my_const_1,
    MyConst2,
    My_Const_3,
};
```

### 5.5. Пространства имён
Название пространства имён должно начинаться с маленькой буквы, отдельные слова начинаются с маленькой буквы и отделяются символом `_`

**Хорошо**
```cpp
namespace my_namespace { }
```
**Плохо**
```cpp
namespace My_Namespace { }
namespace MyNamespace { }
namespace MY_NAMESPACE { }
```